package com.myGroup.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.myGroup.pojo.Activity;
import com.myGroup.pojo.R;
import com.myGroup.pojo.TakePart;
import com.myGroup.service.ActivityService;
import com.myGroup.service.TakePartService;
import com.myGroup.utils.ThreadLocalUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.annotations.Delete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@Slf4j
@Api(tags = "参加活动相关接口")
@RequestMapping("/act")
public class TakePartController {
    @Autowired
    private TakePartService takePartService;
    @Autowired
    private ActivityService activityService;

    /**
     * 用户选择活动
     *
     * @param activity
     * @return
     */
    @PostMapping()
    @ApiOperation(value = "用户选择活动", notes = "当前登录的用户选择活动参加。PS：如果该活动的已参加人数>需要人数，前端会直接禁用选择活动的按钮。所以这里直接给人数+1了。")
    public R<String> choose(@RequestBody Activity activity) {
        // 拿到当前登录的用户的id
        Map<String , Object> claims = ThreadLocalUtil.get();
        Integer id = (Integer) claims.get("id");
        // log.info("当前用户的id：{}", id);

        // 创建记录
        TakePart takePart = new TakePart();
        takePart.setAId(activity.getId());
        takePart.setUId(id);
        // takePart.setStatus(1); // 看看数据库会不会自己插入

        if (!takePartService.existsByAIdAndUId(takePart.getAId(), takePart.getUId())) {
            takePartService.save(takePart);

            activity.setChoosePeople(activity.getChoosePeople() + 1);
            activityService.updateById(activity);

            return R.success("恭喜你，选择成功！");
        }

        /*
            在MyBatis Plus中实现检查数据是否已存在，然后根据结果决定插入新记录或不执行任何操作，可以通过一下几种方法来实现：

            1. **使用`saveOrUpdate`方法**：
            MyBatis Plus提供了`saveOrUpdate`方法，但是这个方法是根据传入实体的`id`属性来决定是插入还是更新的，如果你的`id`字段是数据库自动生成（比如自增主键），那么这个方法默认总是会尝试插入。

            2. **手动检查然后保存**：
            在调用`save`方法之前，你可以手动查询数据库中是否已存在相同的数据。

            ```java
            // 在takePartService中添加一个方法来检查是否存在
            public boolean existsByAIdAndUId(Long aId, Long uId) {
                // 以下是伪代码，你需要依据你的实际情况来编写查询逻辑
                QueryWrapper<TakePart> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("a_id", aId);
                queryWrapper.eq("u_id", uId);
                return this.count(queryWrapper) > 0;
            }

            // 在保存之前检查
            if (!takePartService.existsByAIdAndUId(takePart.getAId(), takePart.getUId())) {
                takePartService.save(takePart);
            } else {
                // 记录已存在，可以选择返回某种信息或者进行其他操作
            }
            ```

            3. **在数据库中使用唯一约束**：
            如果在数据库层面上，`a_id`和`u_id`字段联合起来应该是唯一的，你可以在数据库中为这两个字段设置一个唯一约束或者唯一索引。这样在尝试插入重复数据时，数据库会抛出一个异常，你可以捕获这个异常并据此决定如何处理。

            4. **使用MyBatis Plus提供的Wrapper API自定义操作**：
            你可以使用MyBatis Plus的`lambdaQuery()`等功能构建一个查询，然后使用`exists()`方法来得到一个布尔值，这个布尔值表示记录是否存在，然后再决定是否插入。

            总之，最简单和最直接的方法通常是第2种方法，手动在插入之前先检查数据是否已存在。而方法3在有数据库约束的情况下可以提供数据库级别的保护，避免了并发插入时可能会遗漏的情况。根据你的具体需求和偏好选择最适合你的方案。
         */


        return R.error("对不起，不能重复选择了...");
    }

    /**
     * 获取用户选择的所有活动
     *
     * @param page
     * @param pageSize
     * @return
     */
    @GetMapping()
    @ApiOperation(value = "获取用户选择的活动", notes = "获取当前用户已选择的所有活动")
    public R<Page> getAll(@RequestParam(defaultValue = "1") Integer page,
                          @RequestParam(defaultValue = "10") Integer pageSize) {
        // 拿到当前登录的用户的id
        Map<String , Object> claims = ThreadLocalUtil.get();
        Integer id = (Integer) claims.get("id");

        LambdaQueryWrapper<TakePart> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TakePart::getUId, id);

        List<TakePart> list = takePartService.list(queryWrapper);
        List<Integer> aIds = new ArrayList<>(); // 该用户选择的所有活动的aId数组
        for (TakePart takePart : list) {
            aIds.add(takePart.getAId());
        }

        LambdaQueryWrapper<Activity> activityLambdaQueryWrapper = new LambdaQueryWrapper<>();

        if (aIds.isEmpty()) {
            // 设置一个永远为false的条件，确保查询结果为空
            activityLambdaQueryWrapper.eq(Activity::getId, -1); // 假设ID为-1的记录永远不存在
        } else {
            activityLambdaQueryWrapper.in(Activity::getId, aIds);
        }

        // 分页构造器
        Page pageInfo = new Page(page, pageSize);
        activityService.page(pageInfo, activityLambdaQueryWrapper);

        return R.success(pageInfo);
    }

    /**
     * 获取用户未选择的所有活动
     *
     * @param page
     * @param pageSize
     * @param name
     * @param place
     * @param org
     * @param begin
     * @param end
     * @return
     */
    @GetMapping("/page2")
    @ApiOperation("活动分页查询（用户未选的活动）")
    public R<Page> page(@RequestParam(defaultValue = "1") Integer page,
                        @RequestParam(defaultValue = "10") Integer pageSize,
                        @ApiParam("活动名称") String name,
                        @ApiParam("活动地点") String place,
                        @ApiParam("活动举办方") String org,
                        @ApiParam(value = "查询开始时间，格式：yyyy-MM-dd", defaultValue = "2023-10-29")
                        @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
                        @ApiParam(value = "查询结束时间，格式：yyyy-MM-dd", defaultValue = "2023-10-31")
                        @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {

        //构造分页构造器
        Page pageInfo = new Page(page, pageSize);

        // 拿到当前登录的用户的id
        Map<String , Object> claims = ThreadLocalUtil.get();
        Integer id = (Integer) claims.get("id");
        //
        LambdaQueryWrapper<TakePart> takePartLambdaQueryWrapper = new LambdaQueryWrapper<TakePart>();
        takePartLambdaQueryWrapper.eq(TakePart::getUId, id);
        List<TakePart> takeParts = takePartService.list(takePartLambdaQueryWrapper);

        List<Integer> activityIds = takeParts.stream()
                .map(TakePart::getAId) // 用户已选活动id数组
                .collect(Collectors.toList());

        //条件限定
        LambdaQueryWrapper<Activity> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.like(StringUtils.isNotEmpty(name), Activity::getName, name)
                .like(StringUtils.isNotEmpty(place), Activity::getPlace, place)
                .like(StringUtils.isNotEmpty(org), Activity::getOrg, org)
                .ge((begin != null), Activity::getBeginTime, begin)
                .le((end != null), Activity::getBeginTime, end)
                .notIn((activityIds.size() != 0), Activity::getId, activityIds);


        //排序
        queryWrapper.orderByAsc(Activity::getId);
        //执行
        activityService.page(pageInfo, queryWrapper);
        return R.success(pageInfo);
    }

    /**
     * 用户取消选择
     *
     * @param activity
     * @return
     */
    @DeleteMapping("cancel")
    @ApiOperation(value = "用户取消活动", notes = "")
    public R<String> cancel(@RequestBody Activity activity) {
        // 拿到当前登录的用户的id
        Map<String , Object> claims = ThreadLocalUtil.get();
        Integer uId = (Integer) claims.get("id");

        // 删除活动记录
        LambdaQueryWrapper<TakePart> takePartLambdaQueryWrapper = new LambdaQueryWrapper<>();
        takePartLambdaQueryWrapper
                .eq(TakePart::getAId, activity.getId()) // aId = activity.getId()
                .eq(TakePart::getUId, uId);             // uId = uId

        takePartService.remove(takePartLambdaQueryWrapper);

        // 活动参加人数-1
        activity.setChoosePeople(activity.getChoosePeople() - 1);
        activityService.updateById(activity);

        return R.success("取消成功！");
    }

    /**
     * TODO：用户获取所有活动的接口，这里直接隐藏用户已经选择的活动，这样用户就不能重复选择了
     */
}
